﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using PackageEditor.Properties;
using System.Security.Cryptography;
using System.Globalization;

namespace PackageEditor
{
    public partial class ResourceForm : Form
    {
        private bool isAddResource = true;
        private ListViewItemEx item = null;

        internal static Dictionary<UInt32, string> nameMap
        {
            get
            {
                Dictionary<uint, string> Map = new Dictionary<uint, string>();
                using (StringReader sr = new StringReader(Resources.Extensions))
                {
                    string s;
                    while ((s = sr.ReadLine()) != null)
                    {

                        if (s.StartsWith(";") || s.StartsWith("*")) continue;
                        string[] type = s.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                        if (type.Length < 2) continue;

                        Map.Add(Convert.ToUInt32(type[0], 16), type[1]);
                    }
                }
                return Map;
            }
        }
        public ResourceForm(bool isaddresource, ref ListViewItemEx item)
        {
            InitializeComponent();
            this.Text = isaddresource ? "Add Resource To Package" : "Resource Entry Detail";
            this.isAddResource = isaddresource;
            this.item = item;
            this.btnOk.Enabled = !isaddresource;
        }

        private void ResourceForm_Load(object sender, EventArgs e)
        {
            this.Icon = Properties.Resources.Icon;
            
            foreach (var kvp in nameMap)
                this.combType.Items.Add(string.Format("{0}    0x{1:X8}", kvp.Value, kvp.Key));
            this.combType.Sorted = true;

            ReadEntry();
            this.combHashType.SelectedIndex = 0;
            // hook events
            EventHandler testHandler = new EventHandler(this.OnElementChanged);
            EventHandler hashHandler = new EventHandler(this.OnHashChanged);
            this.combType.TextChanged += testHandler;
            this.txtGroup.TextChanged += testHandler;
            this.txtInstance.TextChanged += testHandler;
            this.txtName.TextChanged += hashHandler;
            this.combHashType.SelectedIndexChanged += hashHandler;
            
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            if (this.ckbCustomName.Enabled && this.txtName.Text != string.Empty) item.Text = this.txtName.Text;
            item.Compressed = ckbCompress.Enabled;
            item.ResourceInstance = Convert.ToUInt64(txtInstance.Text, 16);
            item.ResourceGroup = Convert.ToUInt32(txtGroup.Text, 16);
            item.ResourceType = this.combType.Items.IndexOf(this.combType.Text) >= 0 ? Convert.ToUInt32(this.combType.Text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[1], 16) : Convert.ToUInt32(this.combType.Text, 16);
            this.DialogResult = System.Windows.Forms.DialogResult.OK;
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
        }

        private void ReadEntry()
        {
            if (isAddResource) return;
            if (item.Text != null) { this.ckbCustomName.Checked = true; this.txtName.Text = item.Text; }
            else { this.ckbCustomName.Checked = false; this.txtName.Text = string.Empty; }
            if (nameMap.ContainsKey(item.ResourceType)) { this.combType.Text = string.Format("{0}    0x{1:X8}", nameMap[item.ResourceType], item.ResourceType); } else { this.combType.Text = "0x" + item.ResourceType.ToString("X8"); }
            this.txtInstance.Text = "0x" + item.ResourceInstance.ToString("X16");
            this.txtGroup.Text = "0x" + item.ResourceGroup.ToString("X8");
            this.ckbCompress.Checked = item.Compressed;
        }


        #region Function Part
        public static UInt64 FNV64Hash(string input)
        {
            return FNV64.GetHash(input);
        }

        public static UInt32 FNV32Hash(string input)
        {
            return FNV32.GetHash(input);
        }

        public static UInt64 CLIPHash(string input)
        {
            return FNV64CLIP.GetHash(input);
        }
        #endregion


        void OnHashChanged(object sender, EventArgs e)
        {
            if (!this.ckbCustomName.Checked) return;
            switch (this.combHashType.Text.ToUpper())
            {
                case "FNV64":
                    this.txtInstance.Text = string.Format("0x{0:X16}", FNV64Hash(this.txtName.Text));
                    break;
                case "FNV32":
                    this.txtInstance.Text = string.Format("0x{0:X16}", FNV32Hash(this.txtName.Text));
                    break;
                case "CLIP":
                    this.txtInstance.Text = string.Format("0x{0:X16}", CLIPHash(this.txtName.Text));
                    break;
            }
        }

        void OnElementChanged(object sender, EventArgs e)
        {
            bool test = true;
            test = test ? UInt32Parse(txtGroup.Text) : false;
            test = test ? UInt64Parse(txtInstance.Text) : false;
            if (this.combType.Items.IndexOf(this.combType.Text) >= 0) { test = test ? true : false; } else { test = test ? UInt32Parse(combType.Text) : false; }
            this.btnOk.Enabled = test;
        }

        public static bool UInt32Parse(string input)
        {
            uint num = 0U;
            if (input.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) input = input.Remove(0, 2);
            return uint.TryParse(input, System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture, out num);
        }

        public static bool UInt64Parse(string input)
        {
            ulong num = 0U;
            if (input.StartsWith("0x"))
                input = input.Remove(0, 2);
            return ulong.TryParse(input, System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture, out num);
        }

        
    }
}
